#pragma region Copyright
/// <copyright>
/// Copyright (c) 2007 Ilia Shramko.
/// Released under the terms of the GNU General Public License.
/// </copyright>
#pragma endregion

#include "stdafx.h"

CComObjectCached<OSHSourceConnector>* OSHSourceConnector::_oshSourceConnector = NULL;

OSHSourceConnector::OSHSourceConnector() : _destruction(false)
{
	ATLTRACE_TS(atlTraceOSHSourceConnector, TraceLevel::Verbose,
		"OSHSourceConnector::OSHSourceConnector() : [0x%08X]\r\n", this);
}

OSHSourceConnector::~OSHSourceConnector()
{
	ATLTRACE_TS(atlTraceOSHSourceConnector, TraceLevel::Verbose,
		"OSHSourceConnector::~OSHSourceConnector([0x%08X])\r\n", this);
	_destruction = true;
	CloseSource();
	Disconnect(NULL);
}

/* static */ HRESULT OSHSourceConnector::GetSingleton(OSHSourceConnector** pp)
{
	if(pp == NULL) return E_POINTER;
	*pp = NULL;

	if(_oshSourceConnector == NULL)
	{
		HRESULT hr = CComObjectCached<OSHSourceConnector>::CreateInstance(&_oshSourceConnector);

		ATLTRACE_TS(atlTraceOSHSourceConnector, TraceLevel::Verbose,
			"OSHSourceConnector::GetSingleton() : [0x%08X] - 0x%08X\r\n", _oshSourceConnector, hr);

		if(FAILED(hr)) return hr;
	}

	_oshSourceConnector->AddRef();
	*pp = _oshSourceConnector;

	return S_OK;
}

HRESULT OSHSourceConnector::Connect(OSHSourceEventSink* eventSink)
{
	if(eventSink != NULL)
		_eventSinks.Add(eventSink);
	if(_oshClient) return S_OK;

	CComPtr<OSHLibrary::IClient> oshClient;
	HRESULT hr = oshClient.CoCreateInstance(__uuidof(OSHLibrary::Client));
	if(FAILED(hr)) return hr;

	ATLTRACE_TS(atlTraceOSHSourceConnector, TraceLevel::Verbose,
		"OSHSourceConnector::Connect() : Created OSH client 0x%08X - 0x%08X\r\n", oshClient.p, hr);

	hr = static_cast<ClientEventsType*>(this)->DispEventAdvise(
		oshClient, &__uuidof(OSHLibrary::_IClientEvents));
	if(FAILED(hr)) return hr;

	hr = oshClient->Connect(NULL);
	if(FAILED(hr))
	{
		ATLTRACE_TS(atlTraceOSHSourceConnector, TraceLevel::Error,
			"OSHSourceConnector::StartMonitoring() : Can't connect to OSH host - 0x%08X\r\n", hr);

		static_cast<ClientEventsType*>(this)->DispEventUnadvise(
			oshClient, &__uuidof(OSHLibrary::_IClientEvents));
		return hr;
	}

	_oshClient = oshClient;

	return hr;
}

HRESULT OSHSourceConnector::Disconnect(OSHSourceEventSink* eventSink)
{
	if(eventSink != NULL)
		_eventSinks.Remove(eventSink);

	if(!_oshClient) return S_OK;
	if(!_destruction && _eventSinks.GetSize() > 0) return S_FALSE;

	HRESULT hr = S_OK;

	ATLTRACE_TS(atlTraceOSHSourceConnector, TraceLevel::Verbose,
		"OSHSourceConnector::Disconnect()\r\n");

	CComPtr<OSHLibrary::IClient> oshClient;
	hr = _oshClient.CopyTo(&oshClient);
	if(FAILED(hr)) return hr;

	hr = oshClient->Disconnect();
	static_cast<ClientEventsType*>(this)->DispEventUnadvise(
		oshClient, &__uuidof(OSHLibrary::_IClientEvents));
	
	_oshClient.Revoke();

	return hr;
}

STDMETHODIMP OSHSourceConnector::OnConnect(BSTR sourceName)
{
	ATLTRACE_TS(atlTraceOSHSourceConnector, TraceLevel::Info,
		"OSHSourceConnector::OnConnect(\"%S\")\r\n", sourceName);

	if(_oshSource)
		CloseSource();

	CComPtr<OSHLibrary::ISource> oshSource;
	HRESULT hr = oshSource.CoCreateInstance(__uuidof(OSHLibrary::Source));
	if(FAILED(hr)) return hr;

	ATLTRACE_TS(atlTraceOSHSourceConnector, TraceLevel::Verbose,
		"OSHSourceConnector::OnConnect() : Created OSH source 0x%08X - 0x%08X\r\n", oshSource.p, hr);

	hr = static_cast<SourceEventsType*>(this)->DispEventAdvise(
		oshSource, &__uuidof(OSHLibrary::_ISourceEvents));
	if(FAILED(hr))
	{
		ATLTRACE_TS(atlTraceOSHSourceConnector, TraceLevel::Error,
			"OSHSourceConnector::OnConnect() : Can't connect to OSH source events - 0x%08X\r\n", hr);
		return hr;
	}

	hr = oshSource->Open(CComVariant(sourceName));
	if(FAILED(hr))
	{
		ATLTRACE_TS(atlTraceOSHSourceConnector, TraceLevel::Error,
			"OSHSourceConnector::OnConnect() : Can't open OSH source - 0x%08X\r\n", hr);
		static_cast<SourceEventsType*>(this)->DispEventUnadvise(
			oshSource, &__uuidof(OSHLibrary::_ISourceEvents));
		return hr;
	}

	_oshSource = oshSource;

	return S_OK;
}

STDMETHODIMP OSHSourceConnector::OnDisconnect()
{
	ATLTRACE_TS(atlTraceOSHSourceConnector, TraceLevel::Info,
		"OSHSourceConnector::OnDisconnect()\r\n");

	if(_oshSource)
		CloseSource();

	return S_OK;
}

STDMETHODIMP OSHSourceConnector::OnPing()
{
	ATLTRACE_TS(atlTraceOSHSourceConnector, TraceLevel::Info,
		"OSHSourceConnector::OnPing()\r\n");

	// Touch _oshClient and _oshSource interfaces,
	// otherwise they will be automaticaly destroyed by COM in 6 minutes of idle mode.

	CComPtr<OSHLibrary::IClient> oshClient;
	HRESULT hr = _oshClient.CopyTo(&oshClient);
	if(FAILED(hr)) return hr;

	OSHLibrary::ConnectionStateEnum state;
	hr = oshClient->get_State(&state);

	IsVisible();

	return S_OK;
}

HRESULT OSHSourceConnector::CloseSource()
{
	if(!_oshSource) return S_OK;

	ATLTRACE_TS(atlTraceOSHSourceConnector, TraceLevel::Info,
		"OSHSourceConnector::CloseSource()\r\n");

	CComPtr<OSHLibrary::ISource> oshSource;
	HRESULT hr = _oshSource.CopyTo(&oshSource);
	ATLASSERT(SUCCEEDED(hr));
	if(FAILED(hr)) return hr;

	oshSource->Close();
	static_cast<SourceEventsType*>(this)->DispEventUnadvise(
		oshSource, &__uuidof(OSHLibrary::_ISourceEvents));

	_oshSource.Revoke();

	return S_OK;
}

STDMETHODIMP OSHSourceConnector::OnShow(OSHLibrary::IBitmap* ppBitmap)
{
	ATLTRACE_TS(atlTraceOSHSourceConnector, TraceLevel::Info,
		"OSHSourceConnector::OnShow(0x%08X)\r\n", ppBitmap);

	for(int i = 0; i < _eventSinks.GetSize(); i++)
		_eventSinks[i]->OnShow(ppBitmap);

	return S_OK;
}

STDMETHODIMP OSHSourceConnector::OnHide()
{
	ATLTRACE_TS(atlTraceOSHSourceConnector, TraceLevel::Info,
		"OSHSourceConnector::OnHide()\r\n");

	for(int i = 0; i < _eventSinks.GetSize(); i++)
		_eventSinks[i]->OnHide();

	return S_OK;
}

STDMETHODIMP OSHSourceConnector::OnRefresh(OSHLibrary::IBitmap* ppBitmap)
{
	ATLTRACE_TS(atlTraceOSHSourceConnector, TraceLevel::Info,
		"OSHSourceConnector::OnRefresh(0x%08X)\r\n", ppBitmap);

	for(int i = 0; i < _eventSinks.GetSize(); i++)
		_eventSinks[i]->OnRefresh(ppBitmap);

	return S_OK;
}

HRESULT OSHSourceConnector::ActivateHost()
{
	if(!_oshClient) return E_UNEXPECTED;

	CComPtr<OSHLibrary::IClient> oshClient;
	HRESULT hr = _oshClient.CopyTo(&oshClient);
	if(FAILED(hr)) return hr;

	return oshClient->ActivateHost();
}

HRESULT OSHSourceConnector::GetOSHBitmap(OSHLibrary::IBitmap** oshBitmap)
{
	if(oshBitmap == NULL) return E_INVALIDARG;
	*oshBitmap = NULL;

	if(!_oshSource)
		return E_UNEXPECTED;

	CComPtr<OSHLibrary::ISource> oshSource;
	HRESULT hr = _oshSource.CopyTo(&oshSource);
	if(FAILED(hr)) return hr;

	return oshSource->GetVisibleBitmap(oshBitmap);
}

bool OSHSourceConnector::IsVisible()
{
	if(!_oshSource)
		return false;

	CComPtr<OSHLibrary::ISource> oshSource;
	HRESULT hr = _oshSource.CopyTo(&oshSource);
	if(FAILED(hr)) return false;

	VARIANT_BOOL visible;
	hr = oshSource->get_Visible(&visible);
	if(FAILED(hr)) return false;
	return (visible == VARIANT_TRUE);
}

bool OSHSourceConnector::IsConnected()
{
	return _oshClient.GetCookie() != NULL;
}

